/**
 * 通过软件实现虚拟软盘
 */
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashMap;

public class Floppy {
    enum MAGNETIC_HEAD {
        MAGNETIC_HEAD_0,
        MAGNETIC_HEAD_1
    };

    public int SECTOR_SIZE = 512;       // 每个扇区512字节
    private int CYLINDER_COUNT = 80;    // 每个盘面80 个柱面(磁道)
    private int SECTOR_COUNT = 18;      // 每个柱面18个扇区
    private MAGNETIC_HEAD magneticHead = MAGNETIC_HEAD.MAGNETIC_HEAD_0;
    private int curCylinder = 0;
    private int curSector = 0;

    private HashMap<Integer, ArrayList<ArrayList<byte[]>>> floppy = new HashMap<Integer, ArrayList<ArrayList<byte[]>>>(); // 每个软盘两个盘面

    public Floppy() {
        initFloppy();
    }

    private void initFloppy() {
        // 每个软盘有两个盘面
        floppy.put(MAGNETIC_HEAD.MAGNETIC_HEAD_0.ordinal(), initFloppyDisk());
        floppy.put(MAGNETIC_HEAD.MAGNETIC_HEAD_1.ordinal(), initFloppyDisk());
    }

    private ArrayList<ArrayList<byte[]>> initFloppyDisk() {
        ArrayList<ArrayList<byte[]>> floppyDisk = new ArrayList<ArrayList<byte[]>>();   // 一个盘面
        for(int i = 0; i < CYLINDER_COUNT; i++) {
            floppyDisk.add(initCylinder());
        }
        return floppyDisk;
    }
    
    private ArrayList<byte[]> initCylinder() {
        // 构造一个柱面，一个柱面有18个扇区
        ArrayList<byte[]> cylinder = new ArrayList<byte[]>();
        for(int i = 0; i < SECTOR_COUNT; i++) {
            byte[] sector = new byte[SECTOR_SIZE];
            cylinder.add(sector);
        }
        return cylinder;
    }

    public void setMagneticHead(MAGNETIC_HEAD head) {
        magneticHead = head;
    }

    public void setCylinder(int cylinder) {
        if(cylinder < 0) {
            this.curCylinder = 0;
        } else if(cylinder >= 80) {
            this.curCylinder = 79;
        } else {
            this.curCylinder = cylinder;
        }
    }

    public void setSector(int sector) {
        // 扇区编号：1-18
        if(sector < 1) {
            this.curSector = 0;
        } else if(sector > 18) {
            this.curSector = 18 - 1;
        } else {
            this.curSector = sector - 1;
        }
    }

    public byte[] readFloppy(MAGNETIC_HEAD head, int cylinder_num, int sector_num) {
        setMagneticHead(head);
        setCylinder(cylinder_num);
        setSector(sector_num);

        ArrayList<ArrayList<byte[]>> disk = floppy.get(this.magneticHead.ordinal());
        ArrayList<byte[]> cylinder = disk.get(this.curCylinder);
        byte[] sector = cylinder.get(this.curSector);

        return sector;
    }

    public void writeFloppy(MAGNETIC_HEAD head, int cylinder_num, int sector_num, byte[] buf) {
        setMagneticHead(head);
        setCylinder(cylinder_num);
        setSector(sector_num);

        ArrayList<ArrayList<byte[]>> disk = floppy.get(this.magneticHead.ordinal());
        ArrayList<byte[]> cylinder = disk.get(this.curCylinder);
        // CSDN 上的写法无效，以下方式可以工作
        byte[] buffer = cylinder.get(this.curSector);
        System.arraycopy(buf, 0, buffer, 0, buf.length);
    }

    public void makeFloppy(String fileName) {
        // 软盘的第1-18个扇区表示磁盘0的0柱面的18个扇区
        // 软盘的第19-36个扇区表示磁盘1的0柱面的18个扇区
        // 软盘的第37-54个扇区表示磁盘0的1柱面的18个扇区
        try{
            DataOutputStream out = new DataOutputStream(new FileOutputStream(fileName));
            for(int cylinder = 0; cylinder < CYLINDER_COUNT; cylinder++) {
                for(int head = 0; head <= MAGNETIC_HEAD.MAGNETIC_HEAD_1.ordinal(); head++) {
                    for(int sector = 1; sector <=SECTOR_COUNT; sector++) {
                        byte[] buf = readFloppy(MAGNETIC_HEAD.values()[head], cylinder, sector);
                        out.write(buf);
                    }
                }
            }
        } catch(Exception e) {
            // TODO: Auto-generated catch block
            e.printStackTrace();
        }
    }
}

